// $Id: transport.c 106 2011-10-29 14:39:06Z cedric.shih@gmail.com $
/*
 * Copyright 2011 Cedric Shih (cedric dot shih at gmail dot com)
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

#include <stdlib.h>
#include <string.h>
#include <errno.h>

#include "log.h"

#include "transport.h"

struct niohttp_transport *niohttp_transport_map_find(
		struct niohttp_transport_map *map, const char *type)
{
	struct niohttp_transport_entry find, *found;

	niohttp_debug("finding transport: %s", type);

	find.type = (char *)type;

	if ((found = RB_FIND(niohttp_transport_map, map, &find))) {
		return &found->transporter;
	} else {
		return NULL;
	}
}

int niohttp_transport_map_add(struct niohttp_transport_map *map,
		const char *type, struct niohttp_transport *transporter)
{
	int rc;
	struct niohttp_transport_entry *entry;

	if (niohttp_transport_map_find(map, type)) {
		rc = EEXIST;
		niohttp_error("already registered: %s", type);
		goto finally;
	}

	niohttp_debug("adding transport: %s", type);

	if (!(entry = (struct niohttp_transport_entry *)
			calloc(1, sizeof(*entry)))) {
		rc = errno ? errno : -1;
		niohttp_error("calloc: %s", strerror(rc));
		goto finally;
	}

	if (!(entry->type = strdup(type))) {
		rc = errno ? errno : -1;
		niohttp_error("strdup: %s", strerror(rc));
		goto finally;
	}

	memcpy(&entry->transporter, transporter, sizeof(entry->transporter));
	RB_INSERT(niohttp_transport_map, map, entry);
	rc = 0;

finally:
	return rc;
}

void niohttp_transport_map_remove(struct niohttp_transport_map *map,
		struct niohttp_transport_entry *entry)
{
	niohttp_debug("removing transport: %p", entry);

	RB_REMOVE(niohttp_transport_map, map, entry);

	if (entry->type) {
		free(entry->type);
	}

	free(entry);
}

void niohttp_transport_map_clear(struct niohttp_transport_map *map)
{
	struct niohttp_transport_entry *entry;

	while ((entry = RB_MIN(niohttp_transport_map, map))) {
		niohttp_transport_map_remove(map, entry);
	}
}

int niohttp_transporter_compare(struct niohttp_transport_entry *a,
		struct niohttp_transport_entry *b)
{
	return strcmp(a->type, b->type);
}

RB_GENERATE(niohttp_transport_map, niohttp_transport_entry, entry,
		niohttp_transporter_compare);
